package com.zzyl.nursing.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.CodeGenerator;
import com.zzyl.nursing.domain.*;
import com.zzyl.nursing.dto.*;
import com.zzyl.nursing.mapper.*;
import com.zzyl.nursing.service.ICheckInService;
import com.zzyl.nursing.vo.CheckInConfigVo;
import com.zzyl.nursing.vo.CheckInDetailVo;
import com.zzyl.nursing.vo.CheckInElderVo;
import com.zzyl.nursing.vo.ElderFamilyVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 入住Service业务层实现类
 * 处理老人入住相关的所有业务逻辑，包括入住申请、信息查询、修改和删除等操作
 *
 * @author LiuLi
 * @date 2025-08-11
 */
@Service
public class CheckInServiceImpl extends ServiceImpl<CheckInMapper, CheckIn> implements ICheckInService {
    // 注入入住记录数据访问层对象
    @Autowired
    private CheckInMapper checkInMapper;
    // 注入老人信息数据访问层对象
    @Autowired
    private ElderMapper elderMapper;
    // 注入床位信息数据访问层对象
    @Autowired
    private BedMapper bedMapper;
    // 注入合同信息数据访问层对象
    @Autowired
    private ContractMapper contractMapper;
    // 注入入住配置信息数据访问层对象
    @Autowired
    private CheckInConfigMapper checkInConfigMapper;


    /**
     * 根据主键查询入住信息
     *
     * @param id 入住记录的主键ID
     * @return 入住信息对象，如果不存在则返回null
     */
    @Override
    public CheckIn selectCheckInById(Long id) {
        // 调用Mapper层方法根据ID查询入住记录
        return checkInMapper.selectById(id);
    }

    /**
     * 查询入住信息列表
     *
     * @param checkIn 查询条件封装对象，包含各种查询参数
     * @return 符合条件的入住信息列表
     */
    @Override
    public List<CheckIn> selectCheckInList(CheckIn checkIn) {
        // 调用Mapper层自定义方法查询入住记录列表
        return checkInMapper.selectCheckInList(checkIn);
    }

    /**
     * 新增入住信息
     *
     * @param checkIn 入住信息对象，包含需要保存的入住数据
     * @return 插入结果影响行数，1表示成功，0表示失败
     */
    @Override
    public int insertCheckIn(CheckIn checkIn) {
        // 调用Mapper层方法插入入住记录
        return checkInMapper.insert(checkIn);
    }

    /**
     * 修改入住信息
     *
     * @param checkIn 入住信息对象，包含需要更新的入住数据
     * @return 更新结果影响行数，1表示成功，0表示失败
     */
    @Override
    public int updateCheckIn(CheckIn checkIn) {
        // 调用Mapper层方法根据ID更新入住记录
        return checkInMapper.updateById(checkIn);
    }

    /**
     * 批量删除入住信息
     *
     * @param ids 需要删除的入住记录主键数组
     * @return 删除结果影响行数，等于成功删除的记录数
     */
    @Override
    public int deleteCheckInByIds(Long[] ids) {
        // 调用MyBatis-Plus提供的批量删除方法
        return checkInMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除单条入住信息
     *
     * @param id 入住记录主键ID
     * @return 删除结果影响行数，1表示成功，0表示失败
     */
    @Override
    public int deleteCheckInById(Long id) {
        // 调用Mapper层方法根据ID删除入住记录
        return checkInMapper.deleteById(id);
    }

    /**
     * 处理入住申请流程
     * 包括校验老人状态、更新床位状态、新增老人信息、合同、入住记录及配置等操作
     * 所有数据库操作在一个事务中执行，任何步骤失败都会回滚
     *
     * @param checkInApplyDto 入住申请数据传输对象，包含老人信息、家属信息、合同信息和配置信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void apply(CheckInApplyDto checkInApplyDto) {
        // 获取入住申请中的老人信息
        CheckInElderDto checkInElderDto = checkInApplyDto.getCheckInElderDto();
        // 从配置信息中获取床位ID
        Long bedId = checkInApplyDto.getCheckInConfigDto().getBedId();
        // 获取老人身份证号码，用于唯一性校验
        String idCardNo = checkInElderDto.getIdCardNo();
        // 获取老人家属信息列表
        List<ElderFamilyDto> elderFamilyDtoList = checkInApplyDto.getElderFamilyDtoList();
        // 获取入住配置信息
        CheckInConfigDto checkInConfigDto = checkInApplyDto.getCheckInConfigDto();
        // 获取合同信息
        CheckInContractDto checkInContractDto = checkInApplyDto.getCheckInContractDto();

        // 1. 根据身份证号码校验老人入住状态
        // 创建查询条件构造器
        LambdaQueryWrapper<Elder> elderWrapper = new LambdaQueryWrapper<>();
        // 设置查询条件：身份证号码等于目标号码，且状态为1(启用)、2(请假)或4(已入住)
        elderWrapper.eq(Elder::getIdCardNo,idCardNo)
                .in(Elder::getStatus, 1,2,4);
        // 执行查询
        Elder elder = elderMapper.selectOne(elderWrapper);
        // 1.1 如果查询到老人记录，表示该老人已在入住状态
        if (elder != null) {
            // 抛出业务异常，阻止重复入住
            throw new BaseException("该老人已入住");
        }

        // 2. 更新床位状态为已占用
        // 根据床位ID查询床位信息
        Bed bed = bedMapper.selectById(bedId);
        // 设置床位状态为1(已占用)
        bed.setBedStatus(1);
        // 调用Mapper层方法更新床位状态
        int rows = bedMapper.updateBedStatusById(bed.getBedStatus(),bedId);
        // 如果更新影响行数为0，表示床位状态更新失败
        if (rows == 0) {
            throw new BaseException("床位状态更新失败");
        }

        // 3. 新增或更新老人信息
        Elder eldere = insertOrUpdateElder(checkInElderDto, bed);
        // 4. 新增合同信息
        insertContract(eldere,checkInContractDto,checkInConfigDto);
        // 5. 新增入住记录
        CheckIn checkIn = insertCheckIn(eldere,checkInConfigDto, elderFamilyDtoList);
        // 6. 新增入住配置
        insertCheckInConfig(checkIn,checkInConfigDto);
    }


    /**
 * 获取入住详情信息
 * 根据入住ID查询入住信息，并返回一个包含入住详情信息的VO对象
 *
 * @param id 入住ID
 * @return 包含入住详情信息的VO对象
 */
@Override
public CheckInDetailVo getDetailById(Long id) {
    // 查询入住记录
    CheckIn checkIn = checkInMapper.selectCheckInById(id);

    // 查询老人信息
    Elder elder = elderMapper.selectById(checkIn.getElderId());

    // 查询入住配置信息
    CheckInConfig checkInConfig = checkInConfigMapper.selectById(checkIn.getId());

    // 查询合同信息
    Contract contract = contractMapper.selectByElderId(checkIn.getElderId());

    // 解析家属信息
    List<ElderFamilyVo> elderFamilyList = JSON.parseArray(checkIn.getRemark(), ElderFamilyVo.class);

    // 封装老人信息VO对象
    CheckInElderVo checkInElderVo = new CheckInElderVo();
    BeanUtils.copyProperties(elder, checkInElderVo);

    // 封装入住配置VO对象
    CheckInConfigVo checkInConfigVo = new CheckInConfigVo();
    BeanUtils.copyProperties(checkInConfig, checkInConfigVo);

    // 封装入住详情VO对象
    CheckInDetailVo checkInDetailVo = new CheckInDetailVo();
    checkInDetailVo.setCheckInElderVo(checkInElderVo);
    checkInDetailVo.setElderFamilyVoList(elderFamilyList);
    checkInDetailVo.setCheckInConfigVo(checkInConfigVo);
    checkInDetailVo.setContract(contract);

    return checkInDetailVo;
}



    /**
     * 新增入住配置信息.
     * 将DTO对象转换为实体对象，并关联到对应的入住记录.
     * 包含床位、房间、楼层、护理等级、押金、护理费用、床位费用、其他费用、医保支付、政府补贴等信息
     *
     * @param checkIn 入住信息对象，用于获取入住ID
     * @param checkInConfigDto 入住配置数据传输对象，包含配置信息
     */
    private void insertCheckInConfig(CheckIn checkIn, CheckInConfigDto checkInConfigDto) {
        // 创建入住配置实体对象
        CheckInConfig checkInConfig = new CheckInConfig();
        // 将DTO属性复制到实体对象
        BeanUtils.copyProperties(checkInConfigDto, checkInConfig);
        // 设置关联的入住ID
        checkInConfig.setCheckInId(checkIn.getId());
        // 调用Mapper层方法插入入住配置记录
        checkInConfigMapper.insert(checkInConfig);
    }

    /**
     * 新增入住记录
     * 将老人信息和配置信息整合，创建入住记录，并将家属信息JSON序列化后存入备注字段
     *
     * @param eldere 老人信息对象，包含老人基本信息
     * @param checkInConfigDto 入住配置数据传输对象，包含入住日期等配置信息
     * @param elderFamilyDtoList 老人家属信息列表
     * @return 新增的入住信息对象，包含自动生成的ID
     */
    private CheckIn insertCheckIn(Elder eldere, CheckInConfigDto checkInConfigDto, List<ElderFamilyDto> elderFamilyDtoList) {
        // 创建入住实体对象
        CheckIn checkIn = new CheckIn();
        // 将老人信息复制到入住对象，排除ID字段
        BeanUtils.copyProperties(eldere, checkIn,"id");
        // 设置老人ID
        checkIn.setElderId(eldere.getId());
        // 设置老人姓名
        checkIn.setElderName(eldere.getName());
        // 设置入住开始日期
        checkIn.setStartDate(checkInConfigDto.getStartDate());
        // 设置入住结束日期
        checkIn.setEndDate(checkInConfigDto.getEndDate());
        // 设置护理等级名称
        checkIn.setNursingLevelName(checkInConfigDto.getNursingLevelName());
        // 将家属信息列表JSON序列化后存入备注字段
        checkIn.setRemark(JSON.toJSONString(elderFamilyDtoList));
        // 设置入住状态为0(待审核)
        checkIn.setStatus(0);
        // 调用Mapper层方法插入入住记录
        checkInMapper.insert(checkIn);
        // 返回新增的入住对象
        return checkIn;
    }

    /**
     * 新增入住合同信息
     * 生成合同编号，关联老人信息和入住日期，创建新的合同记录
     *
     * @param elder 老人信息对象，用于关联合同
     * @param checkInContractDto 合同数据传输对象，包含合同基本信息
     * @param checkInConfigDto 配置信息数据传输对象，包含入住日期信息
     */
    private void insertContract(Elder elder, CheckInContractDto checkInContractDto, CheckInConfigDto checkInConfigDto) {
        // 创建合同实体对象
        Contract contract = new Contract();
        // 将DTO属性复制到实体对象
        BeanUtils.copyProperties(checkInContractDto, contract);
        // 生成唯一合同编号
        contract.setContractNumber(CodeGenerator.generateContractNumber());
        // 设置关联的老人ID
        contract.setElderId(elder.getId().intValue());
        // 设置老人姓名
        contract.setElderName(elder.getName());
        // 设置合同开始日期(与入住开始日期一致)
        contract.setStartDate(checkInConfigDto.getStartDate());
        // 设置合同结束日期(与入住结束日期一致)
        contract.setEndDate(checkInConfigDto.getEndDate());
        // 设置合同状态为0(待生效)
        contract.setStatus(0);
        // 调用Mapper层方法插入合同记录
        contractMapper.insert(contract);
    }

    /**
     * 新增或更新老人信息
     * 如果老人不存在(根据身份证号判断)，则新增；如果已存在，则更新信息
     *
     * @param checkInElderDto 老人信息数据传输对象，包含老人基本信息
     * @param bed 床位信息对象，用于获取床位ID和床位号
     * @return 更新后的老人信息对象
     */
    private Elder insertOrUpdateElder(CheckInElderDto checkInElderDto, Bed bed) {
        // 创建老人实体对象
        Elder elder = new Elder();
        // 将DTO属性复制到实体对象
        BeanUtils.copyProperties(checkInElderDto, elder);
        // 设置床位ID
        elder.setBedId(bed.getId());
        // 设置床位号
        elder.setBedNumber(bed.getBedNumber());
        // 设置老人状态为1(已入住)
        elder.setStatus(1);
        // 创建查询条件构造器
        LambdaQueryWrapper<Elder> elderWrapper = new LambdaQueryWrapper<>();
        // 设置查询条件：身份证号码等于目标号码
        elderWrapper.eq(Elder::getIdCardNo,checkInElderDto.getIdCardNo());
        // 执行查询
        Elder elder1 = elderMapper.selectOne(elderWrapper);
        // 如果老人不存在
        if (Objects.isNull(elder1)) {
            // 新增老人记录
            elderMapper.insert(elder);
        }else {
            // 如果老人已存在，设置ID用于更新
            elder.setId(elder1.getId());
            // 更新老人记录
            elderMapper.updateById(elder);
        }
        // 返回老人对象
        return elder;
    }



}
